//
//  CompositeShape.cpp
//  Ray Tracer
//
//  Created by Kaila, Ashish on 4/7/13.
//  Copyright (c) 2013 Kaila, Ashish. All rights reserved.
//

#include "CompositeShape.h"

CompositeShape::CompositeShape()
: SceneObject(NULL)
{
    
}

// Returns true if world point is contained within the object
bool CompositeShape::contains(const Point3D& worldPoint, const Matrix4x4& worldToModel) const
{
    for (int i = 0; i < _childShapes.size(); i++)
    {
        if (pointContainedInChildShape(worldPoint, worldToModel, i))
        {
            return true;
        }
    }
    
    return false;
}

// Determines whether a world point is contained in shape
bool CompositeShape::pointContainedInChildShape(const Point3D& worldPoint, const Matrix4x4& worldToModel, unsigned int index) const
{
    if (index >= _childShapes.size())
    {
        return false;
    }
    
    Matrix4x4 childWorldToModel = _childShapes[index]->getInvTransform() * worldToModel;
    
    if (_childShapes[index]->contains(worldPoint, childWorldToModel))
    {
        return true;
    }
    
    return false;
}

void CompositeShape::addChildShape(const SceneObject* childShape)
{
    _childShapes.push_back(childShape);
}

// Returns true if an intersection occured, false otherwise.
bool CompositeShape::intersect(Ray3D& ray,
                               const Matrix4x4& worldToModel,
                               const Matrix4x4& modelToWorld) const
{
    // No special logic here, just intersect with all children
    bool intersects = false;
    for (unsigned int i = 0; i < _childShapes.size(); i++)
    {
        intersects |= intersectWithChildShape(ray, i, worldToModel, modelToWorld);
    }
    
    return intersects;
}

// Performs intersection with a specified child object
bool CompositeShape::intersectWithChildShape(Ray3D& ray,
                                             unsigned int childIndex,
                                             const Matrix4x4& worldToModel,
                                             const Matrix4x4& modelToWorld) const
{
    if (childIndex >= _childShapes.size())
    {
        return false;
    }
    
    const SceneObject* childShape = _childShapes[childIndex];
    
    Matrix4x4 childModelToWorld = modelToWorld * childShape->getTransform();
    Matrix4x4 childWorldToModel = childShape->getInvTransform() * worldToModel;

    // Perform intersection.
    return childShape->intersect(ray, childWorldToModel, childModelToWorld);
}